/*
 * Copyright (c) 2010, artur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/**
 * @author artur
 * 
 * Kiddie-OS Java ATA driver
 * 
 */
public class ATADrv {

	public static final int SECTOR_SIZE = 512;
	int ioaddr = 0x1f0;
	int p_mask = 0xfff;
	int vaddr1;
	int vaddr2;
	private byte[] data;
	private byte[] d1 = {0,0};
	private short[] d2 = {0};
	
	/**
	 * Constructor
	 */
	public ATADrv() {
		int r;
		initialize();
		
		r = read32(2276);

		// print out result
		putchar((byte)(r & 0xff));
		putchar((byte)((r >> 8) & 0xff));
		putchar((byte)((r >> 16) & 0xff));
		putchar((byte)((r >> 24) & 0xff));

		return;
	}

	/**
	 * addr is a relative address of the data block
	 */
	public int read32(int addr)
	{
		int res1, res2;
		int lba = addr / ATADrv.SECTOR_SIZE;
		int offst = addr % ATADrv.SECTOR_SIZE;
		
		// align address to 4 byte boundary
		offst &= (int)~(0x3);
		
		/* prepare ATA transaction */
		// Set LBA mode + LBA high bits
		outb(0xE0 | (lba >> 24), vaddr1 + 0x6);
		// request for  sector
		outb(1, vaddr1 + 0x2);
		// set low 0-7 lba
		outb(lba & (int)0xff, vaddr1 + 0x3);
		// set next 8-15 lba bits
		outb((lba >> 8) & (int)0xff, vaddr1 + 0x4);
		// set next 16-23 lba bits
		outb((lba >> 16) & (int)0xff , vaddr1 + 0x5);
		outb(0x20, vaddr1 + 0x7);

		// wait for data availability
		while((inb(vaddr1 + 0x7) & 8) == 0);
				
		// skip leading data 
		for (; offst > 0; offst-=2) inw(vaddr1);
		res1 = inw(vaddr1);
		res2 = inw(vaddr1);
		
		res1 = (res2 << 16) | res1;
		
		return res1;
	}
	
	/**
	 * This initializes UART
	 */
	public int initialize() {
		/* map ATA primary base */
		data = _palloc(ioaddr, 0x10);
		/* map byte array to short array */
		d2 = ba2sa(d1);
		/* get virtual address of ATA base */
		vaddr1 = ba2vaddr(data);
		/* get virtual address of SERIAL1 base */
		vaddr2 = (vaddr1 & (int)~p_mask) + 0x3f8;
		return 0;
	}

	/**
	 * 
	 */
	public static byte[] _palloc(int addr, int size) {
		return palloc(addr, size);
	}

	/**
	 * 
	 */
	private byte putchar(byte b)
	{
		outw(b,vaddr2);
		return b;
	}

	/** maps physical memory from 'addr' to virtual memory space */
	private static native byte[] palloc(int addr, int size);
	/** converts byte array to short array */
	private static native short[] ba2sa(byte[] ba);
	/** converts byte array to int array */
	private static native int[] ba2ia(byte[] ba);
	/** takes physical address of byte array */
	private static native int ba2paddr(byte[] ba);
	/** takes virtual address of byte array */
	private static native int ba2vaddr(byte[] ba);

	/** port IO  */
	private static native void outl(int v, int p);
	private static native void outw(int v, int p);
	private static native void outb(int v, int p);
	private static native int inl(int p);
	private static native int inw(int p);
	private static native int inb(int p);
	
}
